#include "mt6816.h"

static void MT6816_GPIO_Init(void)
{
    GPIO_InitTypeDef	GPIO_InitStructure;

    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE);

    GPIO_PinRemapConfig(GPIO_Remap_SWJ_JTAGDisable,ENABLE);

    /********** CS **********/
    GPIO_InitStructure.GPIO_Pin = MT6816_SPI_CS_PIN;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz;
    GPIO_Init(MT6816_SPI_CS_PORT,&GPIO_InitStructure);

    GPIO_SetBits(MT6816_SPI_CS_PORT,MT6816_SPI_CS_PIN);

    /********** SCK **********/
    GPIO_InitStructure.GPIO_Pin = MT6816_SPI_CLK_PIN;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(MT6816_SPI_CLK_PORT,&GPIO_InitStructure);

    /********** MOSI **********/
    GPIO_InitStructure.GPIO_Pin = MT6816_SPI_MOSI_PIN;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(MT6816_SPI_MOSI_PORT,&GPIO_InitStructure);

    /********** MISO **********/
    GPIO_InitStructure.GPIO_Pin = MT6816_SPI_MISO_PIN;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(MT6816_SPI_MISO_PORT,&GPIO_InitStructure);
}

//SPIx 读写一个字节
//TxData:要写入的字节
//返回值:读取到的字节
static u8 MT6816_SPI_ReadWriteByte(u16 TxData)
{
    u8 retry = 0;

    while (SPI_I2S_GetFlagStatus(MT6816_SPI_Get_SPI,SPI_I2S_FLAG_TXE)==RESET) //检查指定的SPI标志位设置与否:发送缓存空标志位
    {
        retry ++;
        if(retry>200)
            return 0;
    }
    SPI_I2S_SendData(MT6816_SPI_Get_SPI,TxData); //通过外设SPIx发送一个数据
    retry = 0;

    while (SPI_I2S_GetFlagStatus(MT6816_SPI_Get_SPI,SPI_I2S_FLAG_RXNE)==RESET) //检查指定的SPI标志位设置与否:接受缓存非空标志位
    {
        retry ++;
        if(retry>200)
            return 0;
    }
    return SPI_I2S_ReceiveData(MT6816_SPI_Get_SPI); //返回通过SPIx最近接收的数据
}

static void MT6816_SPI_Init(void)
{
    SPI_InitTypeDef  		SPI_InitStructure;

    RCC_APB2PeriphClockCmd(RCC_APB2Periph_SPI1,ENABLE);//SPI1时钟使能
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE);

    SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex;//设置SPI单向或者双向的数据模式:SPI设置为双线双向全双工
    SPI_InitStructure.SPI_Mode = SPI_Mode_Master;//设置SPI工作模式:设置为主SPI
    SPI_InitStructure.SPI_DataSize = SPI_DataSize_16b;//设置SPI的数据大小:SPI发送接收16位帧结构
    SPI_InitStructure.SPI_CPOL = SPI_CPOL_High;//串行同步时钟的空闲状态为高电平
    SPI_InitStructure.SPI_CPHA = SPI_CPHA_2Edge;//串行同步时钟的第二个跳变沿（上升或下降）数据被采样
    SPI_InitStructure.SPI_NSS = SPI_NSS_Soft;//NSS信号由硬件（NSS管脚）还是软件（使用SSI位）管理:内部NSS信号有SSI位控制
    SPI_InitStructure.SPI_BaudRatePrescaler = MT6816_SPI_Prescaler;//定义波特率预分频的值:波特率预分频值为256
    SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;//指定数据传输从MSB位还是LSB位开始:数据传输从MSB位开始
    SPI_InitStructure.SPI_CRCPolynomial = 10;//CRC值计算的多项式
    SPI_Init(MT6816_SPI_Get_SPI,&SPI_InitStructure); //根据SPI_InitStruct中指定的参数初始化外设SPIx寄存器

    SPI_Cmd(MT6816_SPI_Get_SPI,ENABLE); //使能SPI外设

    MT6816_SPI_ReadWriteByte(0xff);//启动传输
}

//GPIO输出
#define MT6816_SPI_CS_H()		(MT6816_SPI_CS_PORT -> BSRR = MT6816_SPI_CS_PIN)
#define MT6816_SPI_CS_L()		(MT6816_SPI_CS_PORT -> BRR  = MT6816_SPI_CS_PIN)

MT6816_SPI_Signal_Typedef	mt6816_spi;

/**
  * @brief  MT6816_SPI采集初始化
  * @param  NULL
  * @retval NULL
**/
void MT6816_SPI_Signal_Init(void)
{
    //采集数据
    mt6816_spi.sample_data = 0;
    //输出数据
    mt6816_spi.angle = 0;

    //配置外设
    MT6816_GPIO_Init();
    MT6816_SPI_Init();
}

/**
  * @brief  MT6816_SPI采集获取角度数据
  * @param  NULL
  * @retval NULL
**/
void MT6816_SPI_Get_AngleData(void)
{
    uint16_t data_t[2];
    uint16_t data_r[2];
    uint8_t h_count;

    data_t[0] = ((0x80|0x03)<<8);
    data_t[1] = ((0x80|0x04)<<8);

    for(uint8_t i=0; i<3; i++)
    {
        //读取SPI数据
        MT6816_SPI_CS_L();
        data_r[0] = MT6816_SPI_ReadWriteByte(data_t[0]);
        MT6816_SPI_CS_H();
        MT6816_SPI_CS_L();
        data_r[1] = MT6816_SPI_ReadWriteByte(data_t[1]);
        MT6816_SPI_CS_H();
        mt6816_spi.sample_data = ((data_r[0] & 0x00FF) << 8) | (data_r[1] & 0x00FF);

        //奇偶校验
        h_count = 0;
        for(uint8_t j=0; j<16; j++)
        {
            if(mt6816_spi.sample_data & (0x0001 << j))
                h_count++;
        }
        if(h_count & 0x01)
        {
            mt6816_spi.pc_flag = false;
        }
        else
        {
            mt6816_spi.pc_flag = true;
            break;
        }
    }

    if(mt6816_spi.pc_flag)
    {
        mt6816_spi.angle = mt6816_spi.sample_data >> 2;
        mt6816_spi.no_mag_flag = (bool)(mt6816_spi.sample_data & (0x0001 << 1));
    }
}

/****************************** MT6816 ******************************/
MT6816_Typedef	mt6816;

/**
  * @brief  MT6816初始化
  * @param  NULL
  * @retval NULL
**/
void MT6816_Init(void)
{
    MT6816_SPI_Signal_Init();		//初始化SPI接口
}

/**
  * @brief  MT6816获取角度数据
  * @param  NULL
  * @retval NULL
**/
void MT6816_Get_AngleData(void)
{
    MT6816_SPI_Get_AngleData();
    mt6816.angle_data = mt6816_spi.angle;
}
